#include <stdio.h>
#include <ctime>
#include <cstdarg>
#include <zqdbif.h>
#include <zqdbmodule.h>

//模块
HZQDB g_module = nullptr;
//记录模块状态，0表示模块不可用，非0表示模块可用
int g_state = 0; 

//日志打印函数，这里简单输出到屏幕
void log_print(int level, char const* const format, ...)
{ 
	char buf[4096] = { 0 };
	int len = 4096;
	auto now = std::chrono::system_clock::now();
	auto now_tt = std::chrono::system_clock::to_time_t(now);
	auto n = std::strftime(buf, len, "%Y-%m-%d %H:%M:%S", std::localtime(&now_tt));
	if (n < len) {
		int millis = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count() % 1000;
		n += snprintf(buf + n, len - n, " %d ", millis);
		if (n < len) {
			va_list arg_list;
			va_start(arg_list, format);
			n += vsnprintf(buf + n, len - n, format, arg_list);
			va_end(arg_list);
		}
	}
	printf("%s\n", buf);
}

int main(int argc, char* argv[])
{
	//设置日志回调函数
	ZQDBLogSet(&log_print);
	//初始化信息（配置和回调函数）
	ZQDB_INF zqdb_inf = { 1, argv[argc - 1]
		, [](HNMSG hmsg, size_t* flags)->int
	{
		//回调函数不要做复杂耗时逻辑...
		return 0;
	}
		, [](HZQDB h, ZQDB_NOTIFY_TYPE notify)
	{
		//回调函数不要做复杂耗时逻辑...
		switch (notify)
		{
		case ZQDB_NOTIFY_STATUS: {
			if (!ZQDBIsDisable(h)) {
				switch (h->type)
				{
				case ZQDB_HANDLE_TYPE_EXCHANGE: {
				} break;
				case ZQDB_HANDLE_TYPE_MODULE: {
					//当模块可用时会回调到这里，即通知外面模块初始化完成（开盘），每个交易日都会回调一次
					g_module = h;
					g_state = 1;
				} break;
				default: {
					//
				} break;
				}
			}
			else {
				switch (h->type)
				{
				case ZQDB_HANDLE_TYPE_EXCHANGE: {
				} break;
				case ZQDB_HANDLE_TYPE_MODULE: {
					//当模块不可用时会回调到这里，即通知外面模块准备初始化（清盘），每个交易日都会回调一次
					g_module = h; 
					g_state = 0;
				} break;
				default: {
					//
				} break;
				}
			}
		} break;
		case ZQDB_NOTIFY_ADD: {
			
		} break;
		case ZQDB_NOTIFY_REMOVE: {

		} break;
		case ZQDB_NOTIFY_UPDATE: {

		} break;
		default:
			break;
		}
	}
	};
	//初始化
	auto rlt = ZQDBInit(&zqdb_inf);
	if (ZQDB_STATUS_OK != rlt) {
		LOG4E("ZQDBInit err=%d", rlt);
		return -1;
	}
	//启动
	rlt = ZQDBStart();
	if (ZQDB_STATUS_OK != rlt) {
		LOG4E("ZQDBStart err=%d", rlt);
		return -2;
	}
	//阻塞等待运行
	ZQDBRun(1, [] {
		switch (g_state)
		{
		case 0: {
			//模块还在初始化，一直等待
			LOG4I("mydbd initing...");
			std::this_thread::sleep_for(std::chrono::seconds(3));
		} break;
		case 1: {
			//模块还在初始化完成，这时可以正常获取数据
			zqdb::ObjectT<tagModuleInfoEx> module(g_module);
			zqdb::AllCode allcode;
			LOG4I("mydbd init sucess. closeday=%d tradingday=%d allcode=%d"
				, module->closeday, module->tradingday, (int)allcode.size());
			//如果是客户端模式且非全市场推送的话，想要获取动态行情数据需要首先订阅行情
			zqdb::Code code("600000", EXCHANGE_SSE);
			if (!code.IsSubscribeAll()) {
				code.Subscribe();
			}
		}
		default: {
			//每10秒获取一次数据并打印到屏幕上
			if (g_state % 10 == 1) {
				PERIODTYPE cycles[] = {
					CYC_1MIN, //1分钟K线
					CYC_5MIN, //5分钟K线
					CYC_DAY, //日K线
				};
				//构造上交所对象
				zqdb::Exchange exchange(EXCHANGE_SSE);
				//构造上交所600000股票行情代码对象
				zqdb::Code code("600000", EXCHANGE_SSE);
				//打印上交所600000股票的代码、市场、行情数据是否有效、最新日期、最新时间
				LOG4I("%s.%s valid=%s tradeday=%d time=%d-%09d price=%.2f", code->Code, code->Exchange
					, (code.IsMarketValid() ? "true" : "false"), exchange->TradeDay, code->Date, code->Time, code->Close);
				for (auto cycle : cycles)
				{
					//构造cycle表示的周期的K线数据对象
					zqdb::Data data(code, cycle, 0
						, ZQDB_DATA_FLAG_SYNC_DATA);
					//获取K线数据长度
					int count = data.GetDataCount();
					int maxcount = data.GetDataMaxCount();
					//获取K线日期数组地址
					auto date = (uint32_t*)data.GetData(mdb::Field(MDB_FIELD_INDEX(ZQDB, KDATA, DATE)));
					//获取K线时间数组地址
					auto time = (uint32_t*)data.GetData(mdb::Field(MDB_FIELD_INDEX(ZQDB, KDATA, TIME)));
					//获取K线收盘价数组地址
					auto close = (double*)data.GetData(mdb::Field(MDB_FIELD_INDEX(ZQDB, KDATA, CLOSE)));
					//打印K线日期、时间、收盘价信息
					if (count < 1) {
						LOG4I("%s.%s %s count=%d maxcount=%d"
							, code->Code, code->Exchange, zqdb::Cycle2Str(cycle)
							, count, maxcount);
					}
					else if (count < 2) {
						LOG4I("%s.%s %s count=%d maxcount=%d time=%d-%06d close=%.2f"
							, code->Code, code->Exchange, zqdb::Cycle2Str(cycle)
							, count, maxcount
							, date[0], time[0], close[0]);
					}
					else {
						LOG4I("%s.%s %s count=%d maxcount=%d first time=%d-%06d close=%.2f, prelast time=%d-%06d close=%.2f, last time=%d-%06d close=%.2f"
							, code->Code, code->Exchange, zqdb::Cycle2Str(cycle)
							, count, maxcount
							, date[0], time[0], close[0]
							, date[count - 2], time[count - 2], close[count - 2]
							, date[count - 1], time[count - 1], close[count - 1]);
					}
				}
			}
			g_state++;
		} break;
		}
	});
	LOG4I("mydbd stoping...");
	//停止
	ZQDBStop(ZQDB_STOP_FLAG_NONE);
	//结束
	ZQDBTerm();
	return 0;
}


